package com.senditcertified.mail.widget.dialog;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.TextView;
import android.widget.Toast;

import com.Utility.MessageManager;
import com.Utility.Utility;
import com.parser.Error_Report;
import com.senditcertified.mail.R;
import com.soap.call.Http_Soap_Call;
import com.views.CustomProgressBar;

public class RecordDialog extends Dialog implements
		android.view.View.OnClickListener {
	static final private double EMA_FILTER = 0.6;
	private MediaRecorder mRecorder = null;
	private MediaPlayer mPlayer = null;
	private File mFile;
	private boolean isRecording = false;
	private boolean isRecorded = false;
	private boolean isPlaying = false;
	private int timeRecorded;
	private Timer mTimer;
	private TextView mTvTime;
	private double mEMA = 0.0;
	private CustomProgressBar mPrgSoundLevel;
	private Timer mSoundTask;
	private String fileName = "";

	public RecordDialog(Context context) {
		super(context);
		mFile = new File(context.getExternalFilesDir("Audio"), "temp.3gp");
		mRecorder = new MediaRecorder();
	}

	public void onDismiss(){
		dismiss();
	}
	
	public static boolean isMicrophoneAvailable(Context context) {
		PackageManager pm = context.getPackageManager();
		return pm.hasSystemFeature(PackageManager.FEATURE_MICROPHONE);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.dialog_record);
		initComponents();
		addListeners();
	}

	private void initComponents() {
		getWindow().getDecorView().setBackgroundColor(Color.TRANSPARENT);
		((TextView) findViewById(R.id.tv_guide1)).setText(Html
				.fromHtml(getContext().getString(R.string.record_guide1)));
		((TextView) findViewById(R.id.tv_guide2)).setText(Html
				.fromHtml(getContext().getString(R.string.record_guide2)));
		((TextView) findViewById(R.id.tv_guide3)).setText(Html
				.fromHtml(getContext().getString(R.string.record_guide3)));
		mTvTime = (TextView) findViewById(R.id.tv_time);
		mPrgSoundLevel = (CustomProgressBar) findViewById(R.id.prg_sound_lv);
		mSoundTask = new Timer();
		mSoundTask.schedule(new TimerTask() {

			@Override
			public void run() {
				Message message = mHandler.obtainMessage(2, getAmplitude());
				mHandler.sendMessage(message);
			}
		}, 0, 100);
	}

	@Override
	protected void onStart() {
		super.onStart();
	}

	private void setTime(int time) {
		int minute = time / 60;
		int hour = minute / 60;
		int second = time % 60;
		String timestr;
		DecimalFormat format = new DecimalFormat("00");
		if (hour == 0) {
			timestr = format.format(minute) + ":" + format.format(second);
		} else {
			timestr = format.format(hour) + ":" + format.format(minute) + ":"
					+ format.format(second);
		}
		mTvTime.setText(timestr);

	}

	private void addListeners() {
		if (!isMicrophoneAvailable(getContext())) {
			findViewById(R.id.tv_msg_no_device).setVisibility(View.VISIBLE);
		} else {
			findViewById(R.id.tv_msg_no_device).setVisibility(View.GONE);
			findViewById(R.id.btn_record).setOnClickListener(this);
			findViewById(R.id.btn_play).setOnClickListener(this);
			findViewById(R.id.btn_stop).setOnClickListener(this);
			findViewById(R.id.btn_save).setOnClickListener(this);
		}
		findViewById(R.id.btn_cancel).setOnClickListener(this);
	}

	private void startPlaying() {
		Toast.makeText(getContext(), "Playing...", Toast.LENGTH_SHORT).show();
		mPlayer = new MediaPlayer();
		try {
			mPlayer.setDataSource(mFile.getAbsolutePath());
			mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

				@Override
				public void onCompletion(MediaPlayer mp) {
					isPlaying = false;
					mTimer.cancel();
					mTimer.purge();
					mTimer = null;
				}
			});
			mPlayer.prepare();
			timeRecorded = -1;
			isPlaying = true;
			mTimer = new Timer();

			mPlayer.start();
			mTimer.schedule(new TimerTask() {

				@Override
				public void run() {
					if (mPlayer != null
							&& mPlayer.getDuration() >= timeRecorded) {
						timeRecorded++;
						mHandler.sendEmptyMessage(1);
					}
				}
			}, 0, 1000);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void stopPlaying() {
		mPlayer.release();
		mPlayer = null;
		isPlaying = false;
		if (mTimer != null) {
			mTimer.cancel();
			mTimer.purge();
			mTimer = null;
		}
	}

	private void startRecording() {

		if (mFile.exists()) {
			mFile.delete();
		}
		try {
			mFile.getParentFile().mkdirs();
			mFile.createNewFile();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
		mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
		mRecorder.setOutputFile(mFile.getAbsolutePath());
		mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);

		try {
			mRecorder.prepare();
			mRecorder.start();
			timeRecorded = 0;
			isRecording = true;
			Toast.makeText(getContext(), "Recording...", Toast.LENGTH_SHORT)
					.show();
			mTimer = new Timer();
			mTimer.schedule(new TimerTask() {

				@Override
				public void run() {
					timeRecorded++;
					mHandler.sendEmptyMessage(1);
				}
			}, 0, 1000);
		} catch (IOException e) {
			Log.e("Record", "prepare() failed");
			Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT)
					.show();
		}

	}

	private Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (msg.what == 1) {
				setTime(timeRecorded);
			} else if (msg.what == 2) {
				double amp = (Double) msg.obj;
				mPrgSoundLevel.setProgress((float) amp);
				Log.d("PROGRESS", String.valueOf(amp));
			}
		};
	};

	private void stopRecording() {
		Toast.makeText(getContext(), "Stoped record", Toast.LENGTH_SHORT)
				.show();
		mRecorder.stop();
		mRecorder.reset();
		isRecorded = true;
		isRecording = false;
		if (mTimer != null) {
			mTimer.cancel();
			mTimer.purge();
			mTimer = null;
		}
	}

	@Override
	public void onClick(View v) {
		int id = v.getId();
		if (id == R.id.btn_cancel) {
			dismiss();
		} else if (id == R.id.btn_record) {
			if (!isRecording) {
				if (mPlayer != null && mPlayer.isPlaying()) {
					mPlayer.stop();
				}
				startRecording();
			}
		} else if (id == R.id.btn_stop) {
			if (isRecording) {
				stopRecording();
			} else if (isPlaying) {
				stopPlaying();
			}
		} else if (id == R.id.btn_play) {
			if (isRecorded && !isRecording && mFile.exists() && !isPlaying) {
				startPlaying();
			}
		} else if (id == R.id.btn_save) {
			if (!isRecorded) {
				MessageManager
						.showToast(getContext(), "You must record first!");
			} else {
				fileName = "audio_" + new Date().getTime() + ".3gp";
				new UploadFileTask().execute(mFile.getAbsolutePath(), fileName);
			}
		} else {
		}
	}

	@Override
	protected void onStop() {
		if (mTimer != null) {
			mTimer.cancel();
			mTimer.purge();
		}
		if (mSoundTask != null) {
			mSoundTask.cancel();
			mSoundTask.purge();
		}
		
		if(null != mRecorder){
			mRecorder.release();
		}
		super.onStop();
	}

	public double getAmplitude() {
		if (mRecorder != null)
			return (mRecorder.getMaxAmplitude() / 1800.0);
		else
			return 0;

	}

	public double getAmplitudeEMA() {
		double amp = getAmplitude();
		mEMA = EMA_FILTER * amp + (1.0 - EMA_FILTER) * mEMA;
		return mEMA;
	}

	private void updateDisplay(double signalEMA) {
		mPrgSoundLevel.setProgress((int) signalEMA);
	}

	private class UploadFileTask extends AsyncTask<String, Void, String> {
		private File uploadFile;
		private Error_Report repor = new Error_Report();
		private ProgressDialog dialog;

		@Override
		protected void onCancelled() {
			if (dialog.isShowing()) {
				dialog.dismiss();
			}
			super.onCancelled();
		}

		@Override
		protected void onPreExecute() {
			dialog = new ProgressDialog(getContext());
			dialog.setMessage(getContext().getString(R.string.uploading));
			dialog.setCancelable(false);
			dialog.show();
		}

		@Override
		protected String doInBackground(String... params) {
			uploadFile = new File(params[0]);
			try {
				if (uploadFile.exists()) {

					byte b[][] = toByteArray(uploadFile, 262144);

					Http_Soap_Call call = Http_Soap_Call.create_connection("",
							getContext());
					if (call != null && b != null) {
						for (int i = 0; i < b.length; i++) {
							call.GetUploadMediResponse(Utility
									.getStringPreference(getContext(),
											"LoginToken", "1"), params[1],
									b[i], i * 262144, repor);
						}

					} else {
						return "No Connection!";
					}

				}
			} catch (Exception e) {
				e.printStackTrace();
				return e.getMessage();
			} catch (OutOfMemoryError e) {
				e.printStackTrace();
				return e.getMessage();
			}

			return "OK";
		}

		@Override
		protected void onPostExecute(String result) {
			if (dialog != null) {
				dialog.dismiss();
				dialog = null;
			}

			if ("OK".equals(result)) {
				MessageManager.showToast(getContext(), "File uploaded!");
				onDismiss();
			} else {
				fileName = "";
				MessageManager.showToast(getContext(), result);
			}
		}

	}

	public byte[][] toByteArray(File file, int byteBlockSize)
			throws IOException {
		if (file.exists()) {
			InputStream in = new FileInputStream(file);
			long noOfBlocks = (long) Math.ceil((double) file.length()
					/ (double) byteBlockSize);
			byte[][] result = new byte[(int) noOfBlocks][byteBlockSize];
			int offset = 0;
			for (int i = 0; i < result.length; i++) {
				result[i] = readByteBlock(in, offset, byteBlockSize);
			}
			return result;
		} else
			return null;
	}

	private byte[] readByteBlock(InputStream in, int offset, int noBytes)
			throws IOException {
		byte[] result = new byte[noBytes];
		in.read(result, offset, noBytes);
		return result;
	}

	public String getFileName() {
		return fileName;
	}
}
